//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

#include "UI/Widgets/Widget.h"

namespace Engine
{
namespace UI
{

	class Label;
	SHARED_POINTER( Label );



	//
	// Label
	//

	class Label : public Widget
	{
		friend struct ::MetaData::LabelCfg;

	// variables
	protected:
		UIImage				_image;
		UIFont				_font;
		string				_text;
		rect				_textMargin;
		vec2				_textPos;
		ETextAlign::type	_textAlign;
		float				_textSize;
		vec2				_minMaxTextSize;
		ColorStyle::EType	_state;
		bool				_autoTextSize;


	// methods
	public:
		Label (EWidget::type wgtType, const EngineSubSystemsRef ess);
		~Label ();

		void SetText (uni_c_string text);

		string const &	GetText () const		{ return _text; }
		
		virtual bool ProcessMessage (const WidgetMsg &msg) override;

		static LabelPtr	New (const EngineSubSystemsRef ess);


	protected:
		bool _Arrange (const WidgetMsg &msg);
		
		bool _OnLoad (const WidgetMsg &msg);

		bool _Update (const WidgetMsg &msg);
		bool _Draw (const WidgetMsg &msg);

		bool _SetColorStyle (const WidgetMsg &msg);
	};


	
/*
=================================================
	constructor
=================================================
*/
	inline Label::Label (EWidget::type wgtType, const EngineSubSystemsRef ess) :
		Widget(wgtType, ess), _textSize(0.0f), _textAlign(ETextAlign::CENTER),
		_state(ColorStyle::IDLE), _autoTextSize(false)
	{}

/*
=================================================
	destructor
=================================================
*/
	inline Label::~Label ()
	{}
	
/*
=================================================
	ProcessMessage
=================================================
*/
	inline bool Label::ProcessMessage (const WidgetMsg &msg)
	{
		typedef WidgetMsg	WM;

		switch ( msg.GetType() )
		{
			case WM::UPDATE	 :			return _Update( msg );
			case WM::DRAW :				return _Draw( msg );
			case WM::ARRANGE :			return _Arrange( msg );
			case WM::ON_LOAD :			return _OnLoad( msg );
			case WM::SET_COLOR_STYLE :	return _SetColorStyle( msg );
		}

		return Widget::ProcessMessage( msg );
	}
	
/*
=================================================
	New
=================================================
*/
	inline LabelPtr  Label::New (const EngineSubSystemsRef ess)
	{
		return BaseObject::_New( new Label( EWidget::LABEL, ess ) );
	}
	
/*
=================================================
	_Update
=================================================
*/
	inline bool Label::_Update (const WidgetMsg &msg)
	{
		if ( not IsVisible() )
			return true;

		_state = _enabled ? ColorStyle::IDLE : ColorStyle::DISABLED;
		
		_CheckChangedOnUpdate( msg );

		_SendToAllAttached( msg );
		return true;
	}
	
/*
=================================================
	_Draw
=================================================
*/
	inline bool Label::_Draw (const WidgetMsg &msg)
	{
		if ( not IsVisible() )
			return true;

		const Graphics::BatchRenderPtr &	br = ESS()->GetGraphicsEngine()->GetBatchRender().ptr();

		if ( _image.IsValid() )
			_image.Draw( br, _region, _state );

		if ( not _text.Empty() )
		{
			_font.SetStyle( _state );
			_font.Draw( _textPos, _text );
		}

		_SendToAllAttached( msg );
		return true;
	}
	
/*
=================================================
	_SetColorStyle
=================================================
*/
	inline bool Label::_SetColorStyle (const WidgetMsg &msg)
	{
		typedef WidgetMsg	WM;

		WM::SetColorStyle const &	scs = msg.To< WM::SetColorStyle >();

		switch ( scs.target )
		{
			case WM::SetColorStyle::FONT_CS :
				_font.SetColorStyle( scs.cs );
				return true;

			case WM::SetColorStyle::IMAGE_CS :
				_image.SetColorStyle( scs.cs );
				return true;
		}
		return false;
	}
	
/*
=================================================
	_OnLoad
=================================================
*/
	inline bool Label::_OnLoad (const WidgetMsg &msg)
	{
		_autoTextSize	= IsZero( _textSize );

		//ASSERT( _minMaxTextSize.x <= _minMaxTextSize.y );

		return Widget::_OnLoad( msg );
	}

/*
=================================================
	_Arrange
=================================================
*/
	inline bool Label::_Arrange (const WidgetMsg &msg)
	{
		typedef WidgetMsg		WM;

		ArrangeHelper const &	helper			= *msg.To< WM::Arrange >().helper;
		WidgetLayout			layout			= helper.GetLayout( _layouts );
		float					font_scale		= 0.0f;
		bool					auto_size		= helper.IsAutoSize( layout );

		usize					len = 0;
		vec2					dim;
		rect					text_margin;
		
		_visibleForLayout = helper.IsVisibleForLayout( _layoutMask );

		if ( not _visibleForLayout )
			return true;

		_image.OnLoad();

		if ( _autoTextSize )
			_textSize = 32.0f;

		helper.CalcFontHeight( font_scale, layout.measure, _textSize );
		_font.SetScale( font_scale );

		if ( _font.GetFont().IsNull() )
			_text.Clear();

		if ( not _text.Empty() )
		{
			_font.GetTextDimensions( _text, dim, len );
			_text.SetLength( len );
		}

		helper.TransformSize( text_margin.LeftBottom(), layout.measure, _textMargin.LeftBottom() );
		helper.TransformSize( text_margin.RightTop(),   layout.measure, _textMargin.RightTop()   );

		if ( auto_size and _autoTextSize )
		{
			if ( not _image.HasTexture() )
				RETURN_ERR( "not supported" );

			layout.size = _image.FrameSize();
			auto_size = false;
		}

		helper.Arrange( _region, layout, _parent->GetRegion(), _parent->GetDockRegion() );
		_textPos = _region.LeftTop() /*+ vec2( text_margin.left, text_margin.top )*/;

		if ( auto_size )
		{
			_textAlign = ETextAlign::CENTER;

			_region.SetSize( vec2(	dim.x + text_margin.left + text_margin.right,
									dim.y + text_margin.bottom + text_margin.top ) );

			_textPos = _region.GetCenter() + vec2( -dim.x, dim.y ) * 0.5f +
						text_margin.LeftTop();
		}
		else
		//if ( not auto_size )
		{
			if ( _autoTextSize and not _text.Empty() )
			{
				dim.x += (text_margin.left + text_margin.right);
				dim.y += (text_margin.bottom + text_margin.top);

				_textSize *= ( _region.GetSize() / dim ).Min();

				if ( IsNotZero( _minMaxTextSize.x ) )
					_textSize = Max( _textSize, _minMaxTextSize.x );

				if ( IsNotZero( _minMaxTextSize.y ) )
					_textSize = Min( _textSize, _minMaxTextSize.y );

				helper.CalcFontHeight( font_scale, layout.measure, _textSize );
				_font.SetScale( font_scale );

				_font.GetTextDimensions( _text, dim, len );
			}

			switch ( _textAlign & ETextAlign::_HORIZONTAL )
			{
				case ETextAlign::LEFT :		_textPos.x = _region.left + text_margin.left;								break;
				case ETextAlign::CENTER_X :	_textPos.x = _region.GetCenter().x - dim.x * 0.5f - text_margin.Width();	break;
				case ETextAlign::RIGHT :	_textPos.x = _region.right - dim.x - text_margin.right;						break;
			}

			switch ( _textAlign & ETextAlign::_VERTICAL )
			{
				case ETextAlign::BOTTOM :	_textPos.y = _region.bottom + dim.y + text_margin.bottom;					break;
				case ETextAlign::CENTER_Y :	_textPos.y = _region.GetCenter().y + dim.y * 0.5f - text_margin.Height();	break;
				case ETextAlign::TOP :		_textPos.y = _region.top - text_margin.top;									break;
			}
		}
		/*
		ASSERT( _textPos.x >= _region.left );
		ASSERT( _textPos.y <= _region.top );
		ASSERT( _textPos.x + dim.x <= _region.right );
		ASSERT( _textPos.y - dim.y >= _region.bottom );*/

		_dockRegion = _region;
		
		if ( _image.IsProportional() and _image.HasTexture() )
		{
			helper.ProportionalImageInRegion( _region, _image.FrameSize(), EAlign::CENTER, _dockRegion );
		}

		_stateChanged = true;

		_SendToAllAttached( msg );
		return true;
	}

/*
=================================================
	SetText
=================================================
*/
	inline void Label::SetText (uni_c_string text)
	{
		_text = text;
		_stateChanged = true;
	}


}	// UI
}	// Engine